package controllers

import (
	"fmt"
	"gogogo/helpers"
	"gogogo/memory"
	"gogogo/models"
	cooo "gogogo/services/dtos"
	"math"
	"math/rand"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/go-redis/redis/v8"
	"github.com/gofiber/fiber/v2"
)

func Shuffle(slc []*models.UserFlower) {
	for i := 1; i < len(slc); i++ {
		r := rand.Intn(i + 1)
		if i != r {
			slc[r], slc[i] = slc[i], slc[r]
		}
	}
}

func Shuffle2(slc []*models.FlowerConfigs) {
	for i := 1; i < len(slc); i++ {
		r := rand.Intn(i + 1)
		if i != r {
			slc[r], slc[i] = slc[i], slc[r]
		}
	}
}

func takeUserPlantFlowers(uid, sex, relation, zipcode, limit int, selectedUserFlower *[]*models.UserFlower, selected *int, totalSelect int) int {
	if *selected >= totalSelect {
		return *selected
	}
	friendsO := models.GetInstance().GetUserFriendsByCondition(uid, sex, zipcode, relation)
	var friendIds []int
	for i := 0; i < len(friendsO); i++ {
		friendIds = append(friendIds, friendsO[i].Id)
	}
	friendFlowers := models.GetInstance().GetFlowersByIds(friendIds)
	Shuffle(friendFlowers)
	fixed := 1
	if limit > len(friendFlowers) {
		fixed = len(friendFlowers)
	} else {
		fixed = limit
	}
	selectedThisRound := 0
	for i := 0; i < fixed; i++ {
		*selectedUserFlower = append(*selectedUserFlower, friendFlowers[i])
		*selected = *selected + 1
		selectedThisRound++
		if *selected >= totalSelect {
			break
		}
	}
	return selectedThisRound
}

func takeStrangerPlantFlowers(sex, zipcode int, limit *int, SameZip bool, selected *int, totalSelect int, selectedUserFlower *[]*models.UserFlower, excludeIds []int) int {
	if *selected >= totalSelect {
		return *selected
	}

	leftFriendFlowerAmount5 := totalSelect - *selected
	if *limit > leftFriendFlowerAmount5 {
		*limit = leftFriendFlowerAmount5
	}
	var x1 []*models.UserFlowersSelect
	if SameZip {
		x1 = models.GetInstance().FindRandomUsersFlowerExcludeBy(excludeIds, sex, *limit, zipcode)
	} else {
		x1 = models.GetInstance().FindRandomUsersFlowerExcludeBy2(excludeIds, sex, *limit, zipcode)
	}
	selectedThisRound := 0
	for i := 0; i < len(x1); i++ {
		*selectedUserFlower = append(*selectedUserFlower, &models.UserFlower{
			Id:      x1[i].Id,
			Uid:     x1[i].Uid,
			Fid:     x1[i].Fid,
			Settime: x1[i].Settime,
			State:   x1[i].State,
			Waterid: x1[i].Waterid,
			Amount:  x1[i].Amount,
		})
		*selected++
		selectedThisRound += 1
		if *selected >= totalSelect {
			break
		}
	}
	*limit -= selectedThisRound
	return selectedThisRound
}

func GolfScene(c *fiber.Ctx, user *models.User, slotResult []int) error {
	if user.Golfnum == 0 {
		// 没有击球次数
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "NO golf times",
			"code":    helpers.ERROR_WRONG_GOLF_TIMES,
		})
	}
	// 查找缓存中是否有场景数据集,如果有整理后发回
	golfScenes := make(map[int]*models.UserFlower)
	k1 := fmt.Sprintf("u%d:golfscene", user.Id)
	val2, err := memory.GetInstance().Get(k1).Result()
	if err == redis.Nil {
		// 键值不存在
		// 开始生成场景数据集,存入缓存
		// 1.取好友异性
		selectedUserFlower := make([]*models.UserFlower, 0)
		selected := 0
		totalSelect := models.GetInstance().DbConfigs.Gp.Totalselect
		sex := user.Sex
		diffsex := 0
		if sex == 1 {
			diffsex = 0
		} else {
			diffsex = 1
		}
		friendFlowerAmount := models.GetInstance().DbConfigs.Gp.Friendfloweramount
		takeUserPlantFlowers(user.Id, diffsex, 1, 0, friendFlowerAmount, &selectedUserFlower, &selected, totalSelect)

		if selected < totalSelect {
			// 1.2.取好友同性
			leftFriendFlowerAmount := friendFlowerAmount - selected
			takeUserPlantFlowers(user.Id, sex, 1, 0, leftFriendFlowerAmount, &selectedUserFlower, &selected, totalSelect)

			if selected < totalSelect {
				// 2.1.取relation=0异性
				leftFriendFlowerAmount2 := totalSelect - selected
				followfloweramount := models.GetInstance().DbConfigs.Gp.Followfloweramount
				if followfloweramount > leftFriendFlowerAmount2 {
					followfloweramount = leftFriendFlowerAmount2
				}
				selectedThisRound := takeUserPlantFlowers(user.Id, diffsex, 0, 0, followfloweramount, &selectedUserFlower, &selected, totalSelect)

				if selected < totalSelect {
					// 2.2.取relation=0同性
					leftFriendFlowerAmount3 := followfloweramount - selectedThisRound
					takeUserPlantFlowers(user.Id, sex, 0, 0, leftFriendFlowerAmount3, &selectedUserFlower, &selected, totalSelect)

					if selected < totalSelect {
						// 3.取同城异性,非同城异性,同城同性,非同城同性
						strangerfloweramount := models.GetInstance().DbConfigs.Gp.Strangerfloweramount
						// 取全服state=0的
						var excludeIds []int
						for i := 0; i < len(selectedUserFlower); i++ {
							excludeIds = append(excludeIds, selectedUserFlower[i].Uid)
						}
						// 同城异性
						takeStrangerPlantFlowers(diffsex, user.Zipcode, &strangerfloweramount, true, &selected, totalSelect, &selectedUserFlower, excludeIds)
						if selected < totalSelect {
							// 3.2 非同城异性
							takeStrangerPlantFlowers(diffsex, user.Zipcode, &strangerfloweramount, false, &selected, totalSelect, &selectedUserFlower, excludeIds)
						}
						if selected < totalSelect {
							// 3.3 同城同性
							takeStrangerPlantFlowers(sex, user.Zipcode, &strangerfloweramount, true, &selected, totalSelect, &selectedUserFlower, excludeIds)
						}
						if selected < totalSelect {
							// 3.4 非同城同性
							takeStrangerPlantFlowers(sex, user.Zipcode, &strangerfloweramount, false, &selected, totalSelect, &selectedUserFlower, excludeIds)
						}

						if selected < totalSelect {
							// 4.都取不到则取系统花,系统花的uid为-1,品质为0
							finalLeft := totalSelect - selected
							// 随机生成不在数据库的品质为0的若干花
							flcfgs := models.GetInstance().GetFlowerConfigWithoutStar(0)
							cfgidx := 0
							cfglen := len(flcfgs)
							Shuffle2(flcfgs)
							for i := 0; i < finalLeft; i++ {
								uf_fake := &models.UserFlower{
									Uid:     -1,
									Id:      -(i + 1),
									Fid:     flcfgs[cfgidx].Id,
									State:   0,
									Waterid: 0,
									Amount:  0,
								}
								selectedUserFlower = append(selectedUserFlower, uf_fake)
								cfgidx++
								if cfgidx >= cfglen {
									cfgidx = 0
								}
							}
						}
					}
				}
			}
		}
		// x 5.根据角色身上的允许获得星币的上限,替换一些star flower为0品质的花

		// 更新角色击球次数到数据库
		updates := make(map[string]interface{})
		updates["golfnum"] = user.Golfnum
		models.GetInstance().UpdateUserByMap(user.Id, updates)

		// 随机打散
		Shuffle(selectedUserFlower)
		// 格式化到 redis
		var sb strings.Builder
		for i := 0; i < len(selectedUserFlower); i++ {
			golfScenes[i] = selectedUserFlower[i]
			sb.WriteString(fmt.Sprintf("%d,%d,%d,%d,%d,%d",
				selectedUserFlower[i].Id, selectedUserFlower[i].Uid,
				selectedUserFlower[i].Fid, selectedUserFlower[i].State,
				selectedUserFlower[i].Waterid, selectedUserFlower[i].Amount))
			if i != len(selectedUserFlower)-1 {
				sb.WriteString("&")
			}
		}
		memory.GetInstance().Set(k1, sb.String(), 0)
	} else if err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "DB ERROR",
			"code":    helpers.ERROR_REDIS_ERROR,
		})
	} else {
		// 解析字符串还原场景
		// userflower&userflower2&userflower3...
		// 1,2,3,4,6,121&-2,3,32,45&121,212,121...
		arr1 := strings.Split(val2, "&")
		for i := 0; i < len(arr1); i++ {
			arr_inner := strings.Split(arr1[i], ",")
			if len(arr_inner) < 6 {
				return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
					"success": false,
					"message": "DB ERROR",
					"code":    helpers.ERROR_REDIS_ERROR,
				})
			}
			ufid, _ := strconv.Atoi(arr_inner[0])
			ufuid, _ := strconv.Atoi(arr_inner[1])
			uffid, _ := strconv.Atoi(arr_inner[2])
			ufstate, _ := strconv.Atoi(arr_inner[3])
			ufwaterid, _ := strconv.Atoi(arr_inner[4])
			ufamount, _ := strconv.Atoi(arr_inner[5])
			uf := &models.UserFlower{
				Id:      ufid,
				Uid:     ufuid,
				Fid:     uffid,
				State:   ufstate,
				Waterid: ufwaterid,
				Amount:  ufamount,
			}
			golfScenes[i] = uf
		}
	}

	return c.Status(fiber.StatusOK).JSON(fiber.Map{
		"success": true,
		"data": fiber.Map{
			"golfScene":    golfScenes,
			"hitBallTimes": user.Golfnum,
			"slotArray":    slotResult,
			"slotWinType":  2,
			"energy": user.Energy,
		},
	})
}

func Slot(c *fiber.Ctx) error {

	fmt.Sprintf("XXXXXXXXXXX")


	var body cooo.BaseRequestWithInt
	err := c.BodyParser(&body)

	if err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "Cannot parse JSON",
			"code":    helpers.ERROR_JSON_PARSE_ERROR,
		})
	} else {
		tmpSlotResult := make([]int, 9)
		for i := 0; i < 9; i++ {
			tmpSlotResult[i] = rand.Intn(9) + 1
		}
		// slotWinningType := helpers.SLOT_WINNING_GOLF
		slotWinningType := helpers.SLOT_WINNING_SEED
		fmt.Sprintf("slotWinningType%d", slotWinningType)

		u := models.GetInstance().GetUser(body.Id)
		if u.Id == 0 {
			return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
				"success": false,
				"message": "user not exist",
				"code":    helpers.ERROR_USER_NOT_EXIST,
			})
		}
		if u.Energy>0 {
			models.GetInstance().ReduceEnergy(body.Id,1)
			u = models.GetInstance().GetUser(body.Id)
		}else{
			return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
				"success": false,
				"message": "user energy is zero",
				"code":    helpers.ERROR_EMERYGY_IS_ZERO,
			})
		}


		if slotWinningType == helpers.SLOT_WINNING_SEED {
			// 检索用户的剩余星币奖励数量
			leftStarPrize := int(u.Allowstar) - u.Getstar
			// todo,种子品级 0-6目前写死后面配置
			rand.Seed(time.Now().UnixNano())
			seedRank := rand.Intn(7)
			cfgs := models.GetInstance().GetFlowerConfig(seedRank, leftStarPrize)
			if len(cfgs) <= 0 {
				return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
					"success": false,
					"message": "config not exist",
					"code":    helpers.ERROR_CONFIG_ERROR,
				})
			}
			// 根据开出每种鲜花的几率，随机开出鲜花的种类记录在flower plant中
			totalWeight := 0
			totalCfg := len(cfgs)
			weightRange := make([]int, len(cfgs))
			for i := 0; i < totalCfg; i++ {
				totalWeight += cfgs[i].Weight2
				w1 := 0
				for j := 0; j <= i; j++ {
					w1 += cfgs[j].Weight2
				}
				weightRange[i] = w1
			}
			w := rand.Intn(totalWeight)
			lootIdx := totalCfg - 1
			for i := 0; i < len(weightRange); i++ {
				if i == 0 {
					if w >= 0 && w < weightRange[i] {
						lootIdx = i
						break
					}
				} else {
					if w >= weightRange[i-1] && w < weightRange[i] {
						lootIdx = i
						break
					}
				}
			}
			lootPlant := cfgs[lootIdx]
			// 计算能获得的鲜花数
			lootAmount := lootPlant.Plantamount
			extraAmount := 0
			updates := make(map[string]interface{})
			if lootPlant.Type == 0 {
				// 非星星花
				// 根据技能表获得加成extraAmount
				skillLv := u.Skilllv
				skillCfg := models.GetInstance().DbConfigs.FlowerAddConfigs[skillLv]
				if skillCfg == nil {
					return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
						"success": false,
						"message": "config not exist",
						"code":    helpers.ERROR_CONFIG_ERROR,
					})
				}
				// 理论值Allowflower,实际值Getflower
				var allowAddN float64
				if float64(u.Getflower) >= u.Allowflower {
					A := skillCfg.Plantaddmin
					var B float64
					if lootPlant.Quality == 0 {
						B = skillCfg.Plantadd0
					} else if lootPlant.Quality == 1 {
						B = skillCfg.Plantadd1
					} else if lootPlant.Quality == 2 {
						B = skillCfg.Plantadd2
					} else if lootPlant.Quality == 3 {
						B = skillCfg.Plantadd3
					} else if lootPlant.Quality == 4 {
						B = skillCfg.Plantadd4
					} else if lootPlant.Quality == 5 {
						B = skillCfg.Plantadd5
					} else if lootPlant.Quality == 6 {
						B = skillCfg.Plantadd6
					}
					allowAddN = B
					BX := int(math.Floor(B))
					if A > BX {
						extraAmount = 0
					}
					rand.Seed(time.Now().UnixNano())
					BX2 := BX - A + 1
					if BX2 <= 0 {
						extraAmount = 0
					} else {
						extraAmount = rand.Intn(BX-A+1) + A
					}

				} else {
					var C float64
					D := skillCfg.Plantaddmax
					if lootPlant.Quality == 0 {
						C = skillCfg.Plantadd0
					} else if lootPlant.Quality == 1 {
						C = skillCfg.Plantadd1
					} else if lootPlant.Quality == 2 {
						C = skillCfg.Plantadd2
					} else if lootPlant.Quality == 3 {
						C = skillCfg.Plantadd3
					} else if lootPlant.Quality == 4 {
						C = skillCfg.Plantadd4
					} else if lootPlant.Quality == 5 {
						C = skillCfg.Plantadd5
					} else if lootPlant.Quality == 6 {
						C = skillCfg.Plantadd6
					}
					allowAddN = C
					CX := int(math.Ceil(C))
					if CX > D {
						extraAmount = 0
					}
					rand.Seed(time.Now().UnixNano())
					CX2 := D - CX + 1
					if CX2 <= 0 {
						extraAmount = 0
					} else {
						extraAmount = rand.Intn(D-CX+1) + CX
					}
				}
				updates["getflower"] = u.Getflower + extraAmount
				updates["allowflower"] = u.Allowflower + float64(allowAddN)
			} else {
				updates["getstar"] = u.Getstar + lootPlant.Plantamount
			}
			lootAmount = lootAmount + extraAmount
			// 插入用户植物表
			models.GetInstance().CreateLootedSeed(body.Id, lootPlant.Id, lootAmount)
			// 更新用户
			models.GetInstance().UpdateUserByMap(u.Id, updates)

			return c.Status(fiber.StatusOK).JSON(fiber.Map{
				"success": true,
				"data": fiber.Map{
					"getPlant":    lootPlant,
					"slotArray":   tmpSlotResult,
					"slotWinType": 1,
					"energy": u.Energy,
				},
			})
		} else if slotWinningType == helpers.SLOT_WINNING_GOLF {
			// todo 其他slot奖励
			hittimes := rand.Intn(6)
			// mapping 0,1,2,3,4,5 to 1,2,3,4,5,8
			if hittimes == 5 {
				hittimes = 8
			} else {
				hittimes += 1
			}
			u.Golfnum = hittimes
			return GolfScene(c, u, tmpSlotResult)
		}
		return nil
	}
}

func UFlowers(c *fiber.Ctx) error {
	var body cooo.BaseRequestWithInt

	err := c.BodyParser(&body)

	if err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "Cannot parse JSON",
			"code":    helpers.ERROR_JSON_PARSE_ERROR,
		})
	}

	datas := models.GetInstance().GetUserFlowers(body.Id)
	if datas == nil {
		datas = make([]*models.UserFlowersResult, 0)
	}
	return c.Status(fiber.StatusOK).JSON(fiber.Map{
		"success": true,
		"data": fiber.Map{
			"datas": datas,
		},
	})
}

func AdGetSeed(c *fiber.Ctx) error {
	var body cooo.BaseRequestWithInt

	err := c.BodyParser(&body)

	if err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "Cannot parse JSON",
			"code":    helpers.ERROR_JSON_PARSE_ERROR,
		})
	}

	u := models.GetInstance().GetUser(body.Id)
	if u.Id == 0 {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "user not exist",
			"code":    helpers.ERROR_USER_NOT_EXIST,
		})
	}
	lastAdTime := u.Advertisingtime
	adCd := models.GetInstance().DbConfigs.Gp.Advertisingcd
	okTime := lastAdTime.Add(time.Second * time.Duration(adCd))
	now := time.Now()
	if now.Before(okTime) {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "ad is cooling down",
			"code":    helpers.ERROR_AD_CD_ERROR,
		})
	}

	k1 := fmt.Sprintf("u%d:adtag", body.Id)
	// 记录请求秒数
	memory.GetInstance().Set(k1, time.Now().Unix(), 0)
	updates := make(map[string]interface{})
	updates["advertisingtime"] = time.Now()
	models.GetInstance().UpdateUserByMap( body.Id, updates)
	return c.Status(fiber.StatusOK).JSON(fiber.Map{
		"success": true,
		"data": fiber.Map{
			"canShowAd": true,
		},
	})
}

func AdGetSeed2(c *fiber.Ctx) error {
	var body cooo.AdShow

	err := c.BodyParser(&body)

	if err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "Cannot parse JSON",
			"code":    helpers.ERROR_JSON_PARSE_ERROR,
		})
	}

	u := models.GetInstance().GetUser(body.Uid)
	if u.Id == 0 {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "user not exist",
			"code":    helpers.ERROR_USER_NOT_EXIST,
		})
	}
	lastAdTime := u.Advertisingtime
	adCd := models.GetInstance().DbConfigs.Gp.Advertisingcd
	okTime := lastAdTime.Add(time.Second * time.Duration(adCd))
	now := time.Now()
	if now.Before(okTime) {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "ad is cooling down",
			"code":    helpers.ERROR_AD_CD_ERROR,
		})
	}
	k1 := fmt.Sprintf("u%d:adtag", body.Uid)
	// 记录请求秒数
	lastRequestTimeStamp, err := memory.GetInstance().Get(k1).Int64()
	if err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "ERR",
			"code":    helpers.ERROR_UNKNOW_ERROR,
		})
	}

	nowts := time.Now().Unix()
	if nowts-lastRequestTimeStamp < int64(models.GetInstance().DbConfigs.Gp.Advertisingplay) {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "AD PLAY NOT ENOUGH",
			"code":    helpers.ERROR_AD_PLAY_NOTENOUGH_ERROR,
		})
	}

	// 假设到这里播放完了,给种子
	rand.Seed(time.Now().UnixNano())
	seedRank := rand.Intn(7)
	cfgs := models.GetInstance().GetFlowerConfigWithoutStar(seedRank)
	if len(cfgs) <= 0 {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "config not exist",
			"code":    helpers.ERROR_CONFIG_ERROR,
		})
	}

	// 根据开出每种鲜花的几率，随机开出鲜花的种类记录在flower plant中
	totalWeight := 0
	totalCfg := len(cfgs)
	weightRange := make([]int, len(cfgs))
	for i := 0; i < totalCfg; i++ {
		totalWeight += cfgs[i].Weight2
		w1 := 0
		for j := 0; j <= i; j++ {
			w1 += cfgs[j].Weight2
		}
		weightRange[i] = w1
	}
	w := rand.Intn(totalWeight)
	lootIdx := totalCfg - 1
	for i := 0; i < len(weightRange); i++ {
		if i == 0 {
			if w >= 0 && w < weightRange[i] {
				lootIdx = i
				break
			}
		} else {
			if w >= weightRange[i-1] && w < weightRange[i] {
				lootIdx = i
				break
			}
		}
	}

	lootPlant := cfgs[lootIdx]
	// 计算能获得的鲜花数
	lootAmount := lootPlant.Plantamount
	extraAmount := 0
	updates := make(map[string]interface{})
	if lootPlant.Type == 0 {
		// 非星星花
		// 根据技能表获得加成extraAmount
		skillLv := u.Skilllv
		skillCfg := models.GetInstance().DbConfigs.FlowerAddConfigs[skillLv]
		if skillCfg == nil {
			return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
				"success": false,
				"message": "config not exist",
				"code":    helpers.ERROR_CONFIG_ERROR,
			})
		}
		// 理论值Allowflower,实际值Getflower
		var allowAddN float64
		if float64(u.Getflower) >= u.Allowflower {
			A := skillCfg.Plantaddmin
			var B float64
			if lootPlant.Quality == 0 {
				B = skillCfg.Plantadd0
			} else if lootPlant.Quality == 1 {
				B = skillCfg.Plantadd1
			} else if lootPlant.Quality == 2 {
				B = skillCfg.Plantadd2
			} else if lootPlant.Quality == 3 {
				B = skillCfg.Plantadd3
			} else if lootPlant.Quality == 4 {
				B = skillCfg.Plantadd4
			} else if lootPlant.Quality == 5 {
				B = skillCfg.Plantadd5
			} else if lootPlant.Quality == 6 {
				B = skillCfg.Plantadd6
			}
			allowAddN = B
			BX := int(math.Floor(B))
			if A > BX {
				extraAmount = 0
			}
			rand.Seed(time.Now().UnixNano())
			BX2 := BX - A + 1
			if BX2 <= 0 {
				extraAmount = 0
			} else {
				extraAmount = rand.Intn(BX-A+1) + A
			}

		} else {
			var C float64
			D := skillCfg.Plantaddmax
			if lootPlant.Quality == 0 {
				C = skillCfg.Plantadd0
			} else if lootPlant.Quality == 1 {
				C = skillCfg.Plantadd1
			} else if lootPlant.Quality == 2 {
				C = skillCfg.Plantadd2
			} else if lootPlant.Quality == 3 {
				C = skillCfg.Plantadd3
			} else if lootPlant.Quality == 4 {
				C = skillCfg.Plantadd4
			} else if lootPlant.Quality == 5 {
				C = skillCfg.Plantadd5
			} else if lootPlant.Quality == 6 {
				C = skillCfg.Plantadd6
			}
			allowAddN = C
			CX := int(math.Ceil(C))
			if CX > D {
				extraAmount = 0
			}
			rand.Seed(time.Now().UnixNano())
			CX2 := D - CX + 1
			if CX2 <= 0 {
				extraAmount = 0
			} else {
				extraAmount = rand.Intn(D-CX+1) + CX
			}
		}
		updates["getflower"] = u.Getflower + extraAmount
		updates["allowflower"] = u.Allowflower + float64(allowAddN)
	}
	lootAmount = lootAmount + extraAmount
	// 插入用户植物表
	ufId := models.GetInstance().CreateLootedSeed(body.Uid, lootPlant.Id, lootAmount)
	// 更新用户
	// 增加玩家星币价值
	updates["allowstar"] = u.Allowstar + models.GetInstance().DbConfigs.Gp.AdvertisingStar
	models.GetInstance().UpdateUserByMap(u.Id, updates)

	advertisingcd:= models.GetInstance().DbConfigs.Gp.Advertisingcd
	return c.Status(fiber.StatusOK).JSON(fiber.Map{
		"success": true,
		"getPlant": fiber.Map{
			"Id":      ufId,
			"Uid":     body.Uid,
			"Fid":     lootPlant.Id,
			"State":   0,
			"Waterid": 0,
			"Amount":  0,
		},
		"advertisingcd":advertisingcd,
	})
}

func PayWater(c *fiber.Ctx) error {
	var body cooo.FlowerOp
	err := c.BodyParser(&body)

	if err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "Cannot parse JSON",
			"code":    helpers.ERROR_JSON_PARSE_ERROR,
		})
	}
	uf := models.GetInstance().GetFlower(body.Fid)
	if uf.Id == 0 {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "flower not exist",
			"code":    helpers.ERROR_FLOWER_NOTEXIST,
		})
	}
	if uf.State != 0 {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "flower watered",
			"code":    helpers.ERROR_FLOWER_WATERED,
		})
	}

	u := models.GetInstance().GetUser(body.Uid)
	if u.Id == 0 {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "user not exist",
			"code":    helpers.ERROR_USER_NOT_EXIST,
		})
	}

	if u.Stone < models.GetInstance().DbConfigs.Gp.Watercostdiamond {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "diamond not enough",
			"code":    helpers.ERROR_DIAMOND_NOTENOUGH,
		})
	}

	// 更新用户
	updates := make(map[string]interface{})
	updates["stone"] = u.Stone - models.GetInstance().DbConfigs.Gp.Watercostdiamond
	models.GetInstance().UpdateUserByMap(u.Id, updates)

	// 更新浇花状态
	uf.State = 1
	// uf.Waterid = u.Id
	models.GetInstance().WaterFlowerStage(body.Fid, 1)
	return c.Status(fiber.StatusOK).JSON(fiber.Map{
		"success": true,
		"data": fiber.Map{
			"newFlower": uf,
			"userMoney": updates["stone"],
		},
	})
}

func ReceiveFlowers(c *fiber.Ctx) error {
	var body cooo.FlowerOp
	err := c.BodyParser(&body)

	if err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "Cannot parse JSON",
			"code":    helpers.ERROR_JSON_PARSE_ERROR,
		})
	}

	u := models.GetInstance().GetUser(body.Uid)
	if u.Id == 0 {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "user not exist",
			"code":    helpers.ERROR_USER_NOT_EXIST,
		})
	}

	uf := models.GetInstance().GetFlowerDoneByOwner(body.Fid)
	if uf.Id == 0 {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "flower not exist",
			"code":    helpers.ERROR_FLOWER_NOTEXIST,
		})
	}
	if uf.Uid != body.Uid {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "no your flower",
			"code":    helpers.ERROR_FLOWER_NOT_BELONGTO,
		})
	}

	// 更改鲜花状态为2
	uf.State = 2
	// models.GetInstance().WaterFlowerStage(body.Fid, 2)
	models.GetInstance().DeleteFlowerStage(body.Fid, 2)
	// 增加玩家背包中的鲜花道具
	flowerCfg := models.GetInstance().GetFlowerConfigByid(uf.Fid)
	if flowerCfg.Id == 0 {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "config not exist",
			"code":    helpers.ERROR_CONFIG_ERROR,
		})
	}
	if flowerCfg.Type == helpers.FLOWER_TYPE_FLOWER {
		models.GetInstance().GotOneUserItem(body.Uid, flowerCfg.Floweritem, uf.Amount, helpers.ITEM_TYPE_FLOWER)
	} else {
		// 增加角色星币
		u.Star += uf.Amount
		updates := make(map[string]interface{})
		updates["star"] = u.Star
		models.GetInstance().UpdateUserByMap(body.Uid, updates)
	}
	// 增加玩家友好度
	if uf.Waterid != 0 {
		// 自己浇花的不做这个处理
		userfriend := models.GetInstance().ExistRelations(body.Uid, uf.Waterid)
		if len(userfriend) == 0 {
			// 不存在好友关系,创建好友关系
			models.GetInstance().CreateRelation(body.Uid, uf.Waterid, flowerCfg.Friendly)
			// 创建另一侧的好友关系
			models.GetInstance().CreateRelation(uf.Waterid, body.Uid, flowerCfg.Friendly)
		} else {
			// 更新好友度
			ids := make([]int, len(userfriend))
			for i := 0; i < len(userfriend); i++ {
				ids[i] = userfriend[i].Id
			}
			models.GetInstance().UpdateRelations(ids, map[string]interface{}{"friendly": userfriend[0].Friendly + flowerCfg.Friendly})
		}
	}

	return c.Status(fiber.StatusOK).JSON(fiber.Map{
		"success": true,
		"data": fiber.Map{
			// "newFlower":           uf,
			"flowerId":            body.Fid,
			"addFlowerItemId":     flowerCfg.Floweritem,
			"addFlowerItemAmount": uf.Amount,
			"userStar":            u.Star,
		},
	})
}

func Golf(c *fiber.Ctx) error {
	var body cooo.BaseRequestWithInt
	err := c.BodyParser(&body)

	if err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "Cannot parse JSON",
			"code":    helpers.ERROR_JSON_PARSE_ERROR,
		})
	}
	u := models.GetInstance().GetUser(body.Id)
	if u.Id == 0 {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "user not exist",
			"code":    helpers.ERROR_USER_NOT_EXIST,
		})
	}
	return GolfScene(c, u, nil)
}

func GolfWater(c *fiber.Ctx) error {
	var body cooo.GolfOp
	err := c.BodyParser(&body)

	if err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "Cannot parse JSON",
			"code":    helpers.ERROR_JSON_PARSE_ERROR,
		})
	}
	u := models.GetInstance().GetUser(body.Uid)
	if u.Id == 0 {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "user not exist",
			"code":    helpers.ERROR_USER_NOT_EXIST,
		})
	}
	if u.Golfnum <= 0 {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "no golf times",
			"code":    helpers.ERROR_NOGOLF_TIMES,
		})
	}
	// 获取高尔夫场景
	// 如果不存在或者失败,清空打球次数
	k1 := fmt.Sprintf("u%d:golfscene", body.Uid)
	val2, err := memory.GetInstance().Get(k1).Result()
	var getItemId int
	var getItemAmount int
	var configFlowerId int
	watered := false
	var targetUser *models.User
	targetUser = nil
	if err != nil {
		u.Golfnum = 0
		updates := make(map[string]interface{})
		updates["golfnum"] = 0
		models.GetInstance().UpdateUserByMap(body.Uid, updates)
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"success": false,
			"message": "no golf times",
			"code":    helpers.ERROR_NOGOLF_TIMES,
		})
	} else {
		updates := make(map[string]interface{})
		golfScenes := make(map[int]*models.UserFlower)
		// 解码还原对象
		arr1 := strings.Split(val2, "&")
		for i := 0; i < len(arr1); i++ {
			arr_inner := strings.Split(arr1[i], ",")
			if len(arr_inner) < 6 {
				return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
					"success": false,
					"message": "DB ERROR",
					"code":    helpers.ERROR_REDIS_ERROR,
				})
			}
			ufid, _ := strconv.Atoi(arr_inner[0])
			ufuid, _ := strconv.Atoi(arr_inner[1])
			uffid, _ := strconv.Atoi(arr_inner[2])
			ufstate, _ := strconv.Atoi(arr_inner[3])
			ufwaterid, _ := strconv.Atoi(arr_inner[4])
			ufamount, _ := strconv.Atoi(arr_inner[5])
			uf := &models.UserFlower{
				Id:      ufid,
				Uid:     ufuid,
				Fid:     uffid,
				State:   ufstate,
				Waterid: ufwaterid,
				Amount:  ufamount,
			}
			golfScenes[i] = uf
		}

		var f *models.UserFlower
		for _, v := range golfScenes {
			if v.Id == body.Plantid {
				f = v
				break
			}
		}

		if f != nil {
			if f.Uid != -1 {
				// 用户花
				// 检测是否已经浇过水
				flower := models.GetInstance().GetFlower(f.Id)
				if flower.Id == 0 || flower.State == 1 {
					watered = true
				}
				// 没有浇过水
				// 更新浇水状态 state为1
				models.GetInstance().WaterFlowerStage(flower.Id, 1)
				// 查询用户信息出来
				targetUser = models.GetInstance().FindUserSpec(f.Uid)
			} else {
				// 系统花
				if f.State == 1 {
					watered = true
				}
			}
			if !watered {
				f.State = 1
				flowerCfg := models.GetInstance().GetFlowerConfigByid(f.Fid)
				configFlowerId = f.Fid
				if flowerCfg.Id == 0 {
					return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
						"success": false,
						"message": "config not exist",
						"code":    helpers.ERROR_CONFIG_ERROR,
					})
				}

				// 浇水获得 water amount
				lootAmount := flowerCfg.Wateramount
				extraAmount := 0
				if flowerCfg.Type == 0 {
					// 非星星花
					// 根据技能表获得加成extraAmount
					skillLv := u.Skilllv
					skillCfg := models.GetInstance().DbConfigs.FlowerAddConfigs[skillLv]
					if skillCfg == nil {
						return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
							"success": false,
							"message": "config not exist",
							"code":    helpers.ERROR_CONFIG_ERROR,
						})
					}
					// 理论值Allowflower,实际值Getflower
					var allowAddN float64
					if float64(u.Getflower) >= u.Allowflower {
						A := skillCfg.Wateraddmin
						var B float64
						if flowerCfg.Quality == 0 {
							B = skillCfg.Wateradd0
						} else if flowerCfg.Quality == 1 {
							B = skillCfg.Wateradd1
						} else if flowerCfg.Quality == 2 {
							B = skillCfg.Wateradd2
						} else if flowerCfg.Quality == 3 {
							B = skillCfg.Wateradd3
						} else if flowerCfg.Quality == 4 {
							B = skillCfg.Wateradd4
						} else if flowerCfg.Quality == 5 {
							B = skillCfg.Wateradd5
						} else if flowerCfg.Quality == 6 {
							B = skillCfg.Wateradd6
						}
						allowAddN = B
						BX := int(math.Floor(B))
						if A > BX {
							extraAmount = 0
						}
						rand.Seed(time.Now().UnixNano())
						BX2 := BX - A + 1
						if BX2 <= 0 {
							extraAmount = 0
						} else {
							extraAmount = rand.Intn(BX-A+1) + A
						}

					} else {
						var C float64
						D := skillCfg.Wateraddmax
						if flowerCfg.Quality == 0 {
							C = skillCfg.Wateradd0
						} else if flowerCfg.Quality == 1 {
							C = skillCfg.Wateradd1
						} else if flowerCfg.Quality == 2 {
							C = skillCfg.Wateradd2
						} else if flowerCfg.Quality == 3 {
							C = skillCfg.Wateradd3
						} else if flowerCfg.Quality == 4 {
							C = skillCfg.Wateradd4
						} else if flowerCfg.Quality == 5 {
							C = skillCfg.Wateradd5
						} else if flowerCfg.Quality == 6 {
							C = skillCfg.Wateradd6
						}
						allowAddN = C
						CX := int(math.Ceil(C))
						if CX > D {
							extraAmount = 0
						}
						rand.Seed(time.Now().UnixNano())
						CX2 := D - CX + 1
						if CX2 <= 0 {
							extraAmount = 0
						} else {
							extraAmount = rand.Intn(D-CX+1) + CX
						}
					}
					updates["getflower"] = u.Getflower + extraAmount
					updates["allowflower"] = u.Allowflower + float64(allowAddN)
					// 添加道具
					// 增加玩家背包中的鲜花道具
					lootAmount = lootAmount + extraAmount
					getItemId = flowerCfg.Floweritem
					if getItemId <= 0 {
						getItemId = 2000000
					}
					getItemAmount = lootAmount
					models.GetInstance().GotOneUserItem(body.Uid, flowerCfg.Floweritem, lootAmount, helpers.ITEM_TYPE_FLOWER)

				} else {
					// 星星花,确认角色能收多少,todo
					leftStarPrize := int(u.Allowstar) - u.Getstar
					if leftStarPrize > 0 {
						if lootAmount > leftStarPrize {
							lootAmount = leftStarPrize
						}
						updates["getstar"] = u.Getstar + lootAmount
						updates["star"] = u.Star + lootAmount
					}
				}
			}
		} else {
			return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
				"success": false,
				"message": "Golf logic error",
				"code":    helpers.ERROR_GOLF_WRONGPARSE,
			})
		}
		// 更新用户浇水次数,获得的花数
		u.Golfnum -= 1
		if u.Golfnum < 0 {
			u.Golfnum = 0
		}
		// updates := make(map[string]interface{})
		updates["golfnum"] = u.Golfnum
		models.GetInstance().UpdateUserByMap(body.Uid, updates)
		// 如果次数为0,清除场景
		if u.Golfnum <= 0 {
			memory.GetInstance().Del(k1)
		} else {
			// 如果还有次数,结构写回redis
			if !watered {
				var sb strings.Builder
				l := len(golfScenes)
				idx := 0
				keys := make([]int, l)
				i := 0
				for k := range golfScenes {
					keys[i] = k
					i++
				}
				sort.Ints(keys)
				for k := 0; k < l; k++ {
					v := golfScenes[keys[k]]
					sb.WriteString(fmt.Sprintf("%d,%d,%d,%d,%d,%d",
						v.Id, v.Uid,
						v.Fid, v.State,
						v.Waterid, v.Amount))
					if idx != l-1 {
						sb.WriteString("&")
					}
					idx++
				}
				memory.GetInstance().Set(k1, sb.String(), 0)
			}
		}
	}

	if targetUser == nil {
		return c.Status(fiber.StatusOK).JSON(fiber.Map{
			"success":        true,
			"isWatered":      watered,
			"newTimes":       u.Golfnum,
			"userStar":       u.Star,
			"getItemId":      getItemId,
			"flowerid":       body.Plantid,
			"configid":       configFlowerId,
			"getItemAmount":  getItemAmount,
			"targetUserId":   0,
			"targetUserName": "",
		})
	}
	return c.Status(fiber.StatusOK).JSON(fiber.Map{
		"success":        true,
		"isWatered":      watered,
		"newTimes":       u.Golfnum,
		"userStar":       u.Star,
		"getItemId":      getItemId,
		"flowerid":       body.Plantid,
		"configid":       configFlowerId,
		"getItemAmount":  getItemAmount,
		"targetUserId":   targetUser.Id,
		"targetUserName": targetUser.Nname,
	})
}
